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 Robust PID and Prepare for removing ARM DSP dependency #29

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4003a5d
start transitioning to embedded C++
alvinsunyixiao Jan 14, 2021
173bb98
override malloc
alvinsunyixiao Jan 15, 2021
19d3e41
Merge remote-tracking branch 'origin/master' into alvin/cpp17
alvinsunyixiao Jan 15, 2021
387e6ee
format code
alvinsunyixiao Jan 15, 2021
74eeafa
eigen not quite working
alvinsunyixiao Jan 15, 2021
f6b2364
remove third party ignore
alvinsunyixiao Jan 15, 2021
c1304e8
seems to be working
alvinsunyixiao Jan 15, 2021
a439bf5
format code
alvinsunyixiao Jan 15, 2021
db5a15b
Merge remote-tracking branch 'origin/master' into alvin/eigen
alvinsunyixiao Jan 16, 2021
498a03f
fix bad merge
alvinsunyixiao Jan 16, 2021
f35b225
make eigen a seperate interface lib
alvinsunyixiao Jan 16, 2021
8ccc123
try string stream again
alvinsunyixiao Jan 16, 2021
1097d09
Merge remote-tracking branch 'origin/master' into alvin/eigen
alvinsunyixiao Jan 17, 2021
ea89c76
address comment and add realloc wrapper
alvinsunyixiao Jan 17, 2021
e100346
Merge branch 'alvin/eigen' of github.com:illini-robomaster/iRM_Embedd…
alvinsunyixiao Jan 17, 2021
a09363e
re implement robust pid
alvinsunyixiao Jan 17, 2021
a065028
add comment
alvinsunyixiao Jan 17, 2021
0a21699
untested robust pid
alvinsunyixiao Jan 17, 2021
5433bb6
fix equation
alvinsunyixiao Jan 20, 2021
ba9686e
Merge remote-tracking branch 'origin/master' into alvin/eigen
alvinsunyixiao Jan 20, 2021
3f8e96e
Merge remote-tracking branch 'origin/alvin/eigen' into alvin/controller
alvinsunyixiao Jan 20, 2021
7b48ba1
add debug target to RelWithDebInfo
alvinsunyixiao Jan 20, 2021
fe7912a
Merge remote-tracking branch 'origin/alvin/eigen' into alvin/controller
alvinsunyixiao Jan 20, 2021
b0559d1
reduce dynamic alloc
alvinsunyixiao Jan 21, 2021
111dae5
Merge remote-tracking branch 'origin/master' into alvin/controller
alvinsunyixiao Jan 24, 2021
328e1af
fix merge error
alvinsunyixiao Jan 24, 2021
255227f
fix build
alvinsunyixiao Jan 24, 2021
e106ba4
format code
alvinsunyixiao Jan 24, 2021
82c3706
remove arm_math header
alvinsunyixiao Jan 26, 2021
3971d0a
format code
alvinsunyixiao Jan 27, 2021
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
27 changes: 13 additions & 14 deletions examples/motor/m3508.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* *
****************************************************************************/

#include <memory>

#include "bsp_gpio.h"
#include "bsp_print.h"
#include "cmsis_os.h"
Expand All @@ -27,28 +29,25 @@
#define KEY_GPIO_GROUP GPIOB
#define KEY_GPIO_PIN GPIO_PIN_2

bsp::CAN* can1 = NULL;
control::MotorCANBase* motor = NULL;
void RM_RTOS_Default_Task(const void* args) {
UNUSED(args);

void RM_RTOS_Init() {
print_use_uart(&huart8);

can1 = new bsp::CAN(&hcan1, 0x201);
motor = new control::Motor3508(can1, 0x201);
}
auto can1 = std::make_shared<bsp::CAN>(&hcan1, 0x201);
auto motor = std::make_unique<control::Motor3508>(can1, 0x201);
auto key = std::make_unique<bsp::GPIO>(KEY_GPIO_GROUP, GPIO_PIN_2);

void RM_RTOS_Default_Task(const void* args) {
UNUSED(args);
control::MotorCANBase* motors[] = {motor};
const std::vector<control::MotorCANBase*> motors = {motor.get()};

bsp::GPIO key(KEY_GPIO_GROUP, GPIO_PIN_2);
while (1) {
motor->PrintData();
if (key.Read())
const uint32_t start = osKernelSysTick();
if (key->Read())
motor->SetOutput(800);
else
motor->SetOutput(0);
control::MotorCANBase::TransmitOutput(motors, 1);
osDelay(100);
control::MotorCANBase::TransmitOutput(motors);
motor->PrintData();
osDelayUntil(start + 10);
}
}
34 changes: 13 additions & 21 deletions examples/motor/m3508_speed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,27 @@
#define KEY_GPIO_PIN GPIO_PIN_2

#define TARGET_SPEED 80

bsp::CAN* can1 = NULL;
control::MotorCANBase* motor = NULL;

void RM_RTOS_Init() {
print_use_uart(&huart8);

can1 = new bsp::CAN(&hcan1, 0x201);
motor = new control::Motor3508(can1, 0x201);
}
#define CONTROL_DT 10

void RM_RTOS_Default_Task(const void* args) {
UNUSED(args);
control::MotorCANBase* motors[] = {motor};
control::PIDController pid(20, 8, 0);

bsp::GPIO key(KEY_GPIO_GROUP, GPIO_PIN_2);
print_use_uart(&huart8);

auto can1 = std::make_shared<bsp::CAN>(&hcan1, 0x201);
auto motor = std::make_unique<control::Motor3508>(can1, 0x201);
auto pid = std::make_unique<control::PIDController>(20, 0.01, 1, CONTROL_DT / 1e3, 20);
auto key = std::make_unique<bsp::GPIO>(KEY_GPIO_GROUP, KEY_GPIO_PIN);

float target;
const std::vector<control::MotorCANBase*> motors = {motor.get()};

while (1) {
if (key.Read())
target = TARGET_SPEED;
else
target = 0;
const uint32_t start = osKernelSysTick();
const float target = key->Read() ? TARGET_SPEED : 0;

motor->SetOutput(pid.ComputeOutput(motor->GetOmegaDelta(target)));
control::MotorCANBase::TransmitOutput(motors, 1);
motor->SetOutput(pid->ComputeOutput(motor->GetOmegaDelta(target)));
control::MotorCANBase::TransmitOutput(motors);
motor->PrintData();
osDelay(10);
osDelayUntil(start + CONTROL_DT);
}
}
29 changes: 15 additions & 14 deletions examples/motor/m6623.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* *
****************************************************************************/

#include <memory>

#include "bsp_gpio.h"
#include "bsp_print.h"
#include "cmsis_os.h"
Expand All @@ -27,28 +29,27 @@
#define KEY_GPIO_GROUP GPIOB
#define KEY_GPIO_PIN GPIO_PIN_2

bsp::CAN* can1 = NULL;
control::MotorCANBase* motor = NULL;
void RM_RTOS_Default_Task(const void* args) {
UNUSED(args);

void RM_RTOS_Init() {
print_use_uart(&huart8);

can1 = new bsp::CAN(&hcan1, 0x201);
motor = new control::Motor6623(can1, 0x209);
}
auto can1 = std::make_shared<bsp::CAN>(&hcan1, 0x201);
auto motor = std::make_unique<control::Motor6623>(can1, 0x209);
auto key = std::make_unique<bsp::GPIO>(KEY_GPIO_GROUP, KEY_GPIO_PIN);

void RM_RTOS_Default_Task(const void* args) {
UNUSED(args);
control::MotorCANBase* motors[] = {motor};
const std::vector<control::MotorCANBase*> motors = {motor.get()};

bsp::GPIO key(KEY_GPIO_GROUP, GPIO_PIN_2);
while (1) {
motor->PrintData();
if (key.Read())
const uint32_t start = osKernelSysTick();

if (key->Read())
motor->SetOutput(400);
else
motor->SetOutput(0);
control::MotorCANBase::TransmitOutput(motors, 1);
osDelay(100);

control::MotorCANBase::TransmitOutput(motors);
motor->PrintData();
osDelayUntil(start + 10);
}
}
1 change: 1 addition & 0 deletions shared/bsp/bsp_memory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* *
****************************************************************************/

#include <cassert>
#include <cstddef>

#include "cmsis_os.h"
Expand Down
26 changes: 19 additions & 7 deletions shared/libraries/controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@

namespace control {

PIDController::PIDController(float kp, float ki, float kd) {
pid_f32_.Kp = kp;
pid_f32_.Ki = ki;
pid_f32_.Kd = kd;
arm_pid_init_f32(&pid_f32_, 1);
}
PIDController::PIDController(float kp, float ki, float kd, float N, float dt)
: a0_(1 + N * dt),
uc1_((2 + N * dt) / a0_),
uc2_(-1 / a0_),
ec0_(kp + (ki * dt * a0_ + kd * N) / a0_),
ec1_(-(kp * (2 + N * dt) + ki * dt + 2 * kd * N) / a0_),
ec2_((kp + kd * N) / a0_) {}

float PIDController::ComputeOutput(float error) {
// compute output
float u0 = uc1_ * u1_ + uc2_ * u2_ + ec0_ * error + ec1_ * e1_ + ec2_ * e2_;

float PIDController::ComputeOutput(float error) { return arm_pid_f32(&pid_f32_, error); }
// update state
e2_ = e1_;
e1_ = error;
u2_ = u1_;
u1_ = u0;

return u0;
}

} /* namespace control */
26 changes: 17 additions & 9 deletions shared/libraries/controller.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
#pragma once

/* NOTE(alvin): DSP libraries depends on macro definitions on FPU computability, so the
* main.h must be included before arm_math.h */
// clang-format off
#include "main.h"
// clang-format on

#include "arm_math.h"

namespace control {

/**
* @brief simple PID controller
* @brief simple PID controller with lowpass filtered derivitive estimates
*/
class PIDController {
public:
Expand All @@ -21,8 +15,10 @@ class PIDController {
* @param kp proportional gain
* @param ki integral gain
* @param kd derivative gain
* @param N derivative lowpass filter bandwidth in [rad / s]
* @param dt sampling time for the control loop in [s]
*/
PIDController(float kp, float ki, float kd);
PIDController(float kp, float ki, float kd, float N, float dt);

/**
* @brief compute output base on current error
Expand All @@ -34,7 +30,19 @@ class PIDController {
float ComputeOutput(float error);

private:
arm_pid_instance_f32 pid_f32_;
// states
float u1_ = 0;
float u2_ = 0;
float e1_ = 0;
float e2_ = 0;

// coefficients
const float a0_;
const float uc1_;
const float uc2_;
const float ec0_;
const float ec1_;
const float ec2_;
};

} /* namespace control */
39 changes: 15 additions & 24 deletions shared/libraries/motor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

#include "motor.h"

#include "arm_math.h"
#include <cmath>

#include "bsp_error_handler.h"
#include "utils.h"

Expand All @@ -33,7 +34,7 @@ static void can_motor_callback(const uint8_t data[], void* args) {
motor->UpdateData(data);
}

MotorCANBase::MotorCANBase(bsp::CAN* can, uint16_t rx_id)
MotorCANBase::MotorCANBase(const std::shared_ptr<bsp::CAN>& can, uint16_t rx_id)
: theta_(0), omega_(0), can_(can), rx_id_(rx_id) {
constexpr uint16_t GROUP_SIZE = 4;
constexpr uint16_t RX1_ID_START = 0x201;
Expand All @@ -51,14 +52,16 @@ MotorCANBase::MotorCANBase(bsp::CAN* can, uint16_t rx_id)
tx_id_ = TX2_ID;
else
tx_id_ = TX1_ID;

can->RegisterRxCallback(rx_id, can_motor_callback, this);
}

void MotorCANBase::TransmitOutput(MotorCANBase* motors[], uint8_t num_motors) {
void MotorCANBase::TransmitOutput(const std::vector<MotorCANBase*>& motors) {
uint8_t data[8] = {0};

RM_ASSERT_GT(num_motors, 0, "Meaningless empty can motor transmission");
RM_ASSERT_LT(num_motors, 4, "Exceeding maximum of 4 motor commands per CAN message");
for (uint8_t i = 0; i < num_motors; ++i) {
RM_ASSERT_GT(motors.size(), 0, "Meaningless empty can motor transmission");
RM_ASSERT_LT(motors.size(), 4, "Exceeding maximum of 4 motor commands per CAN message");
for (uint8_t i = 0; i < motors.size(); ++i) {
RM_ASSERT_EQ(motors[i]->tx_id_, motors[0]->tx_id_, "tx id mismatch");
RM_ASSERT_EQ(motors[i]->can_, motors[0]->can_, "can line mismatch");
const uint8_t motor_idx = (motors[i]->rx_id_ - 1) % 4;
Expand All @@ -73,25 +76,21 @@ void MotorCANBase::TransmitOutput(MotorCANBase* motors[], uint8_t num_motors) {
float MotorCANBase::GetTheta() const { return theta_; }

float MotorCANBase::GetThetaDelta(float target) const {
return wrap<float>(target - theta_, -PI, PI);
return wrap<float>(target - theta_, -M_PI, M_PI);
}

float MotorCANBase::GetOmega() const { return omega_; }

float MotorCANBase::GetOmegaDelta(float target) const { return target - omega_; }

Motor3508::Motor3508(CAN* can, uint16_t rx_id) : MotorCANBase(can, rx_id) {
can->RegisterRxCallback(rx_id, can_motor_callback, this);
}

void Motor3508::UpdateData(const uint8_t data[]) {
const int16_t raw_theta = data[0] << 8 | data[1];
const int16_t raw_omega = data[2] << 8 | data[3];
raw_current_get_ = data[4] << 8 | data[5];
raw_temperature_ = data[6];

constexpr float THETA_SCALE = 2 * PI / 8192; // digital -> rad
constexpr float OMEGA_SCALE = 2 * PI / 60; // rpm -> rad / sec
constexpr float THETA_SCALE = 2 * M_PI / 8192; // digital -> rad
constexpr float OMEGA_SCALE = 2 * M_PI / 60; // rpm -> rad / sec
theta_ = raw_theta * THETA_SCALE;
omega_ = raw_omega * OMEGA_SCALE;
}
Expand All @@ -108,16 +107,12 @@ void Motor3508::SetOutput(int16_t val) {
output_ = clip<int16_t>(val, -MAX_ABS_CURRENT, MAX_ABS_CURRENT);
}

Motor6623::Motor6623(CAN* can, uint16_t rx_id) : MotorCANBase(can, rx_id) {
can->RegisterRxCallback(rx_id, can_motor_callback, this);
}

void Motor6623::UpdateData(const uint8_t data[]) {
const int16_t raw_theta = data[0] << 8 | data[1];
raw_current_get_ = (data[2] << 8 | data[3]) * CURRENT_CORRECTION;
raw_current_set_ = (data[4] << 8 | data[5]) * CURRENT_CORRECTION;

constexpr float THETA_SCALE = 2 * PI / 8192;
constexpr float THETA_SCALE = 2 * M_PI / 8192;
theta_ = raw_theta * THETA_SCALE;
}

Expand All @@ -143,17 +138,13 @@ float Motor6623::GetOmegaDelta(const float target) const {
return 0;
}

Motor2006::Motor2006(CAN* can, uint16_t rx_id) : MotorCANBase(can, rx_id) {
can->RegisterRxCallback(rx_id, can_motor_callback, this);
}

void Motor2006::UpdateData(const uint8_t data[]) {
const int16_t raw_theta = data[0] << 8 | data[1];
const int16_t raw_omega = data[2] << 8 | data[3];
raw_current_get_ = data[4] << 8 | data[5];

constexpr float THETA_SCALE = 2 * PI / 8192; // digital -> rad
constexpr float OMEGA_SCALE = 2 * PI / 60; // rpm -> rad / sec
constexpr float THETA_SCALE = 2 * M_PI / 8192; // digital -> rad
constexpr float OMEGA_SCALE = 2 * M_PI / 60; // rpm -> rad / sec
theta_ = raw_theta * THETA_SCALE;
omega_ = raw_omega * OMEGA_SCALE;
}
Expand Down
Loading