Cube Mini Solution

Dependencies:   mbed QEI MPU6050 BLE_API nRF51822 MCP4725 eMPL_MPU6050

main.cpp

Committer:
BoulusAJ
Date:
2020-05-28
Revision:
12:ba4ce3fa4f53
Parent:
11:af811e6f9a04
Child:
13:41edfb8e3b3c

File content as of revision 12:ba4ce3fa4f53:

/*
    Boulus Abu Joudom
    Version: May 21, 2020. 17:00
    ZHAW - IMS

    Cubiod (Cube Mini) Balancing Experiment - Control Lab
    Using Seeed Tiny Microcontroller
*/
// Libraries
#include "mbed.h"
#include "math.h"
#include "MPU6050.h"
#include "IIR_filter.h"
#include "mcp4725.h"
#include <stdbool.h>
#include "LinearCharacteristics.h"
#include "PID_Cntrl_Old.h"
#include "PID_Cntrl_2.h"

// Serial PC Communication
#define UART_TX     p9
#define UART_RX     p11

// IMU SDA and SCL
#define MPU6050_SDA p12
#define MPU6050_SCL p13

// PI Values
#define PI 3.1415927f
#define pi 3.1415927f

// PC Serial
Serial pc(UART_TX, UART_RX);

// -------------------------------
// Analog/Digitsl I/O Definitions
// -------------------------------
AnalogIn Velocity_Voltage_Input(p5);
DigitalOut Pin_3V3(p30);

// ------------------------------------
// USER INPUT ( Desired Values)
// ------------------------------------
// User Input
float Desired_input = 0.0f;
// Initial System input in Amperes
float Sys_input_Amps = 0.0f;

// ------------------------------------
//  Variables
// ------------------------------------

// Sample time of main loops
float Ts = 0.005;

// MPU 6050 Variables - Acceleration and Gyroscope Raw and Converted Data Variables
int16_t AccX_Raw, AccY_Raw, AccZ_Raw;
int16_t GyroX_Raw, GyroY_Raw, GyroZ_Raw;

double AccX_g, AccY_g, AccZ_g;
double GyroX_Degrees, GyroY_Degrees, GyroZ_Degrees, GyroZ_RadiansPerSecond;

// ------------------------------------

// Angle Variables
double Cuboid_Angle_Radians, Cuboid_Angle_Degrees;
double Cuboid_Angle_Speed_Degrees = 0.0;

// Low pass filter variables
float t = 0.5f;

// printf Variable
int k = 0;
int Case1_Counter = 0;

// Flywheel Position and Velocity variables
double Velocity_Input_Voltage = 0.0f;
double Velocity, Velocity_Voltage, Velocity_rpm, Velocity_Voltage_Read;

// --------------------------------------

//----------------- Controller VARIABLES------------------
// Variables concerning the Controller, the Design is in reference to the Matlab Simulink .............. and Variables are in reference to the ............. File

// Sate Space Controller Values
float K_SS_Controller [2] = {-57.1176*0.3, -2.6398}; // From Matlab

// Controller Variables
float Loop1_output; // Loop 1 controller output
float Loop2_output;  // Loop 2 controller output
float PID_Input, PID_Output;

// Saturation Parameters
// PI Controller Limits
const float uMin1 = -5.0f;
const float uMax1= 5.0f;

// Cuboid Driver Input Limits
const float uMin2 = -13.0f;
const float uMax2= 13.0f;

// Controller Loop 2 (PI-Part)
float Kp_1 = -0.09;
float Ki_1 = -0.09;
float Kd_1 = 0; // No D-Part
float Tf_1 = 1; // No D-Part

// Controller Loop (PI-Part) in Case 2 (breaking case)
float Kp_2 = 4;
float Ki_2 = 80;
float Kd_2 = 0; // No D-Part
float Tf_2 = 1; // No D-Part

// User Button
int Button_Status = 0;

// ---------- Functions -------------

// Interrupts
Ticker  ControllerLoopTimer;            // Interrupt for control loop

// DAC
MCP4725 VoltageOut(p3, p4, MCP4725::Fast400kHz, 0);

// IMU - MPU6050 Functions and I2C Functions
I2C    i2c(MPU6050_SDA, MPU6050_SCL);
MPU6050 mpu(i2c);

// Accelerometer and Gyroscope Filters
IIR_filter FilterAccX(t, Ts, 1.0f);
IIR_filter FilterAccY(t, Ts, 1.0f);
IIR_filter FilterGyro(t, Ts, t);

// Linear Scaler
LinearCharacteristics CurrentToVoltage(-15.0f, 15.0f, 0.0f, 5.0f);
LinearCharacteristics VoltageToVelocity(0.0f, 3.0f, -4000.0f, 4000.0f);

// PID Controllers
PID_Cntrl_Old C1(Kp_1,Ki_1,Kd_1,Tf_1,Ts,uMin1,uMax1);  // Defining the 1st Loop Controller (PI-Part)
PID_Cntrl_Old C2(Kp_2,Ki_2,Kd_2,Tf_2,Ts,uMin1,uMax1);  // Defining the PI Controller for Chase (State 2) to keep motor velocity at zero

// Timers
Timer Loop;

// ----- User defined functions -----------
void updateControllers(void);   // speed controller loop (via interrupt)

//******************************************************************************
//---------- Main Loop -------------
//******************************************************************************
int main()
{
    // Microcontroller initialization
    pc.baud(115200);
    VoltageOut.write(CurrentToVoltage(0));
    Pin_3V3.write(1);
    *((unsigned int *)0x40007504) = 0x400A; // Configure the ADC to the internel reference of 1.2V.
    // IMU - MPU6050 initialization
    mpu.initialize();
    mpu.setDLPFMode(MPU6050_DLPF_BW_20); // Sets Low Pass Filter Bandwidth to 21Hz (8.5ms) for the Acc and 20Hz (8.3ms) for the Gyroscope
    mpu.setFullScaleGyroRange(2u);  // Change the scale of the Gyroscope to +/- 1000 degrees/sec
    mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_4); // Change the scale of the Accelerometer to +/- 4g - Sensitivity: 4096 LSB/mg

    // Reset Filters
    FilterAccX.reset(0.0f);
    FilterAccY.reset(0.0f);
    FilterGyro.reset(0.0f);

    // Reset PID
    C1.reset(0.0f);

    // Control Loop Interrupt at Ts, 200Hz Rate
    ControllerLoopTimer.attach(&updateControllers, Ts);

}
//******************************************************************************
//---------- control loop (called via interrupt) -------------
//******************************************************************************
void updateControllers(void)
{

    // Aquire Raw Acceleration and Gyro Data form the IMU
    mpu.getMotion6(&AccX_Raw, &AccY_Raw, &AccZ_Raw, &GyroX_Raw, &GyroY_Raw, &GyroZ_Raw);

    // Acquire Velocity
    Velocity_Voltage_Read = Velocity_Voltage_Input.read();
    Velocity_Voltage = 3.0*1.1978917*(Velocity_Voltage_Read); // *1.2V because the Vref is 1.2V // *3 because the prescaling is 1/3 // *1.1978917 is for Calibration purposes instead of 1.2
    Velocity_rpm = VoltageToVelocity(Velocity_Voltage);
    Velocity = Velocity_rpm*2.0*pi/60.0;

    // -------------- Convert Raw data to SI Units --------------------

    //Convert Acceleration Raw Data to (ms^-2) - (Settings of +/- 4g)
    AccX_g = AccX_Raw / 8192.0f;
    AccY_g = AccY_Raw / 8192.0f;
    AccZ_g = AccZ_Raw / 8192.0f;

    //Convert Gyroscope Raw Data to Degrees per second
    GyroX_Degrees = GyroX_Raw / 32.768f;  // (2^15/1000 = 32.768)
    GyroY_Degrees = GyroY_Raw / 32.768f;  // (2^15/1000 = 32.768)
    GyroZ_Degrees = GyroZ_Raw / 32.768f;  // (2^15/1000 = 32.768)

    //Convert Gyroscope Raw Data to Degrees per second
    GyroZ_RadiansPerSecond = (GyroZ_Raw / 32.768f)* pi/180.0f;

    // ----- Combine Accelerometer Data and Gyro Data to Get Angle ------

    Cuboid_Angle_Radians =  -1*atan2(-FilterAccX(AccX_g), FilterAccY(AccY_g)) + 0.7854f + FilterGyro(GyroZ_RadiansPerSecond);  // Check later if fast enough!!
    Cuboid_Angle_Degrees = Cuboid_Angle_Radians*180.0f/pi;


    // ------------------------- Controller -----------------------------

    switch(Button_Status) {

        case 0:

            // PI Controller
            PID_Input = Desired_input - Velocity;
            PID_Output = C1.update(PID_Input);

            // System input
            Sys_input_Amps = PID_Output;
            VoltageOut.write(CurrentToVoltage(Sys_input_Amps));

            // Counter of 10 seconds then go to Case 1
            Case1_Counter++;
            if (Case1_Counter > 2000) {
                Button_Status = 1;
            }

        case 1:

            // Current Input Updater - Amperes
            // Loop 1
            Loop1_output = Cuboid_Angle_Radians*K_SS_Controller[0];
            // Loop 2
            Loop2_output = GyroZ_RadiansPerSecond*K_SS_Controller[1];
            // PI Controller
            //PID_Input = Desired_input - Velocity;
            //PID_Output = C1.update(PID_Input);

            // Constant Speed Control
            //PID_Input = 52.36f - Velocity;
            //PID_Output = C1.update(-1*PID_Input);

            // System input
            Sys_input_Amps = 0.5f; //PID_Output; //- Loop1_output - Loop2_output;
            //VoltageOut.write(0.5f);

            if (Sys_input_Amps > uMax2) {
                Sys_input_Amps = uMax2;
            }
            if (Sys_input_Amps < uMin2) {
                Sys_input_Amps = uMin2;
            }

            // Scaling the controller output from -15 A --> 15 A to 0 V --> 5 V
            VoltageOut.write(CurrentToVoltage(Sys_input_Amps));

    }

    // Print Data
    if(++k >= 10) {
        k = 0;
        pc.printf("Some Outputs: %0.6f, %0.6f\n\r", Sys_input_Amps, Velocity);
    }

    pc.printf("%0.6f, %0.6f\n\r", Sys_input_Amps, Velocity);
}