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

Implement the Simple Vehicle Dynamics Interface in C++ #330

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions firmware/projects/FrontController/inc/simp_vd_interface.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// @author Teghveer Singh Ateliey
/// @date 2024-11-23

#include "simp_vd_interface.h"

using namespace ctrl;

SimpVdInterface::SimpVdInterface(float target_slip)
: target_slip(target_slip) {}

VdOutput SimpVdInterface::update(const VdInput& input, int time_ms) {
VdOutput output{
.lm_torque_limit_negative = 0.0f,
.rm_torque_limit_negative = 0.0f,
.left_motor_speed_request = 1000,
.right_motor_speed_request = 1000
};

motor_torque_request = ComputeTorqueRequest(input.driver_torque_request,
input.brake_pedal_postion);
actual_slip =
CalculateActualSlip(input.wheel_speed_lr, input.wheel_speed_rr,
input.wheel_speed_lf, input.wheel_speed_rf);
tc_scale_factor = CalculateTCScaleFactor(actual_slip, target_slip, time_ms);

float steering_angle = input.tv_enable ? input.steering_angle : 0.0f;
std::tie(tv_factor_left, tv_factor_right) = AdjustTorqueVectoring(
steering_angle, CreateTorqueVectoringFactor(steering_angle));

std::tie(output.lm_torque_limit_positive, output.rm_torque_limit_positive) =
CalculateMotorTorque(motor_torque_request * tc_scale_factor,
tv_factor_right, tv_factor_left);

return output;
}
44 changes: 44 additions & 0 deletions firmware/projects/FrontController/inc/simp_vd_interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// @author Teghveer Singh Ateliey
/// @date 2024-11-23

#pragma once

#include "app.h"
#include "shared/controls/motor_torque.h"
#include "shared/controls/tc_scale_factor.h"
#include "shared/controls/tvFactor.h"

struct VdInput {
float driver_torque_request;
float brake_pedal_postion;
float steering_angle;
float wheel_speed_lr;
float wheel_speed_rr;
float wheel_speed_lf;
float wheel_speed_rf;
bool tv_enable;
};

struct VdOutput {
float lm_torque_limit_positive;
float rm_torque_limit_positive;
float lm_torque_limit_negative;
float rm_torque_limit_negative;
Tegh25 marked this conversation as resolved.
Show resolved Hide resolved
uint16_t left_motor_speed_request;
uint16_t right_motor_speed_request;
};

class SimpVdInterface {
public:
SimpVdInterface(
float target_slip = 0.2f); // default target slip is float 0.2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know c++ had default args, this is cool

VdOutput update(const VdInput& input, int time_ms);

private:
float target_slip;
float motor_torque_request;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these class variables? If possible, make them local to the update function

float actual_slip;
float tc_scale_factor;
float tv_factor_left;
float tv_factor_right;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// tests for the simp_vd_interface class
64 changes: 64 additions & 0 deletions firmware/shared/controls/motor_torque.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once
#include <tuple>

#include "shared/util/moving_average.h"

// Peter Jabra and Aleeza Ali Zar
namespace ctrl {

enum class State {
Run,
Stop,
};

template <typename T>
std::tuple<T, T> CalculateMotorTorque(T new_torque_value, T right_factor,
T left_factor, bool reset = false) {
static shared::util::MovingAverage<T, 10> running_average;

if (reset) {
running_average = shared::util::MovingAverage<T, 10>();
}

running_average.LoadValue(new_torque_value);

T running_average_value = running_average.GetValue();

T right_motor_torque_limit = running_average_value * right_factor;
T left_motor_torque_limit = running_average_value * left_factor;

return std::tuple(right_motor_torque_limit, left_motor_torque_limit);
}

template <typename T>
T ComputeTorqueRequest(T driver_torque_request, T brake_pedal_position) {
static State current_state = State::Stop;
bool brake_on = brake_pedal_position > static_cast<T>(10);

bool both_pedals_pressed =
(driver_torque_request >= static_cast<T>(25) && brake_on);
bool neither_pedal_pressed =
driver_torque_request < static_cast<T>(5) && !brake_on;

if (both_pedals_pressed) {
current_state = State::Stop;
}
if (neither_pedal_pressed) {
current_state = State::Run;
}

T driver_torque;

switch (current_state) {
case State::Run:
driver_torque = driver_torque_request;
break;
case State::Stop:
driver_torque = static_cast<T>(0.0);
break;
}

return driver_torque;
}

} // namespace ctrl
44 changes: 44 additions & 0 deletions firmware/shared/controls/tc_scale_factor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

namespace ctrl {
// Note: The CalculateActualSlip function has Div-by-Zero error if left front
// and right front wheel speeds = 0.
template <typename T>
T CalculateActualSlip(T left_rear_wheel_speed, T right_rear_wheel_speed,
T left_front_wheel_speed, T right_front_wheel_speed) {
T idle_wheel_spd = (left_front_wheel_speed + right_front_wheel_speed) / 2.0;
T actual_slip;

if (left_rear_wheel_speed > right_rear_wheel_speed) {
actual_slip = (left_rear_wheel_speed / idle_wheel_spd) - 1;
} else {
actual_slip = (right_rear_wheel_speed / idle_wheel_spd) - 1;
}

if (actual_slip < 0) {
actual_slip = 0;
}
return actual_slip;
}

template <typename T>
T CalculateTCScaleFactor(T actual_slip, T target_slip, int time_ms) {
// Stateflow: Multi-Stage TC
T scale_factor;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BlakeFreer For the CalculateTCScaleFactor function I assumed that the OS is handled by main.cc, and will call the simp_vd_interface update function at a regular interval. Time_ms will then represent time elapsed, and the TC scale factor will be returned based on that. Let me know if this is the right approach.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also had a couple more questions:

  1. What is this LUT in the simp_vd_interface Simulink subsystem? It looks like it just scales the input by 10, am I right to assume that?
    image
  2. How can I test the subsystem in Simulink, so that I can generate test cases to use for the c++ implementation?

Copy link
Contributor

@BlakeFreer BlakeFreer Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes it looks like a multiply by ten, but that doesn't logically make sense since that implies 1000% torque. I'm guessing that it was a hack because the running average block stores 10 values.

    We will implement it differently for the C++ implementation. You should use the LookupTable from shared/util/mappers/lookup_table. See this file for an example on creating a lookup table. Your table should only have two key-values: 0,0 and 100,100. This means it doesn't actually modify the input, but in the future we will want the ability to modify this curve.

    Replace the entire Running Average block with MovingAverage from shared/util/moving_average. See this file for an example.

  2. I'm not sure how to test simulink, but I don't really trust the model anyways. You should come up with test cases manually. For example, if driver_torque_request=0 then the output torque request should be zero. Don't worry too much about them rn. Just make some simple tests so that we have something to build on later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BlakeFreer For the CalculateTCScaleFactor function I assumed that the OS is handled by main.cc, and will call the simp_vd_interface update function at a regular interval. Time_ms will then represent time elapsed, and the TC scale factor will be returned based on that. Let me know if this is the right approach.

This is mostly correct. time_ms will be the absolute current time, not elapsed. If you want elapsed then make a static variable in your function (static variables don't get reset on successive function calls). Idk if your code actually needs the time, but it's there just in case.


if (time_ms > 50 && time_ms <= 83 && actual_slip > target_slip) {
scale_factor = 0.0f;
}
else if (time_ms > 83 && time_ms <= 116 && actual_slip <= target_slip) {
scale_factor = 0.25f;
}
else if (time_ms > 116 && time_ms <= 149) {
scale_factor = 0.5f;
}
else {
scale_factor = 1.0f;
}

return scale_factor;
}
} // namespace ctrl
44 changes: 44 additions & 0 deletions firmware/shared/controls/tvFactor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once
#include <algorithm>
#include <tuple>
#include "../util/mappers/lookup_table.h"

namespace ctrl{

template <typename T>
T CreateTorqueVectoringFactor(T steering_angle) {
T absolute_steering_angle = std::abs(steering_angle);

static const float table_data[][2] = {
{0.0, 1.0f}, {5.0, 0.934f}, {10.0, 0.87f},
{15.0, 0.808f}, {20.0, 0.747f}, {25.0, 0.683f},
};

static constexpr int table_length =
(sizeof(table_data)) / (sizeof(table_data[0]));

static shared::util::LookupTable<table_length> tv_lookup_table{table_data};

return tv_lookup_table.Evaluate(absolute_steering_angle);
}

template <typename T>
std::tuple<T, T> AdjustTorqueVectoring(T steering_angle,
T torque_vectoring_factor) {
T left_torque_vector;
T right_torque_vector;

if (steering_angle > 0) {
left_torque_vector = static_cast<T>(1);
right_torque_vector = torque_vectoring_factor;
} else if (steering_angle < 0) {
right_torque_vector = static_cast<T>(1);
left_torque_vector = torque_vectoring_factor;
} else {
left_torque_vector = static_cast<T>(1);
right_torque_vector = static_cast<T>(1);
}

return std::tuple(left_torque_vector, right_torque_vector);
}
}
Loading