this code is for inverted pendulum balancer. it is based on two-loop PID controller. One controller is for Angle and another one is for velocity.

Dependencies:   HCSR04 L298HBridge mbed

controller/controller.cpp

Committer:
dudu941014
Date:
2017-08-25
Revision:
0:489498e8dae5

File content as of revision 0:489498e8dae5:

//////////////////////////////////////////////////////////////////////////////////
// Company: edinburgh of university
// Engineer: ZEjun DU
// 
// Create Date: 2017/08/20 13:06:52
// Design Name: Inverted Pendulum Balancer
// Module Name: create the PID struct, and control and manage two PID controllers
// Tool Versions: “Keil 5” or “Mbed Complie Online”
// Description: this part is to get PWM result from two PID controllers
//                           
// 
//////////////////////////////////////////////////////////////////////////////////

#include "controller.h"

PidObject pidAngle;//create Angle PID controller
PidObject pidVelocity;//create Velocity PID controller

static float LastEncoder,Encoder,LastDistance_result;

float AngleOutput;//the angle PID controller's output
float velOutput;//the Velocity PID controller's output
L298HBridge Motor_PWM(p21, p22, p23);//it defines the pins of controlling motor

float Motor;//the PWM result from two PID controller

float I_term;//show the changle of I_term


////////////////////////////////////////////////////////////
//this funcition is to initialize two PID controllers
////////////////////////////////////////////////////////////
void controller_init(void)
{
    pidInit(&pidAngle, 0, 0, 0, 0, 50, controllerAng_update_dt);//to create and initialize angle PID controller
    pidInit(&pidVelocity, 0, 0, 0, 0, 500, controllerVel_Update_dt);//to create and initialize Velocity PID controller
}


////////////////////////////////////////////////////////////
//this funcition is to control and manage the Angle PID controller
//the system can invoke this function to get the result of Angle PWM
////////////////////////////////////////////////////////////
float controller_Angle_PID(float angle_result)
{
  // Update PID for angle
    pidAngle.error = pidAngle.desired - angle_result * 10;// in the actual control, the effect of plusing 0.01 for Kp Ki Kd is too small. thus the error is multiplied 10 rather than change GUI's code 
    if(pidAngle.error > AngleErrLimit)//this part is to limit the error of angle
        pidAngle.error = AngleErrLimit;//if the angle's error is too lager, the result of angle will become limitation
    else if(pidAngle.error < -AngleErrLimit)//this part is to limit the error of angle
        pidAngle.error = -AngleErrLimit;//if the angle's error is too small, the result of angle will become limitation
    AngleOutput = get_pid(&pidAngle);//get the angle output from basic PID control theroy

    if(AngleOutput > AngleOutputLimit)//judge the angle output
        AngleOutput = AngleOutputLimit;//if the angle's output is too lager, the output of the angle PID controller will become limitation
    else if(AngleOutput < -AngleOutputLimit)//judge the angle output
        AngleOutput = -AngleOutputLimit;//if the angle's output is too small, the output of the angle PID controller will become limitation

    return AngleOutput;//return the output of the angle PID controller 
  
}


////////////////////////////////////////////////////////////
//this funcition is to control and manage the Velocity PID controller
//the system can invoke this function to get the result of Velocity PWM
////////////////////////////////////////////////////////////
float controller_Velocity_PID(float Distance_result)
{
    LastEncoder =(Distance_result- LastDistance_result) / controllerVel_Update_dt;   //to calculate the velocity    
    Encoder *= 0.8;            //this equation can be ragarded as a low pass filter, it is used to reduce the effect of Velocity PID controller                                               
    Encoder += LastEncoder*0.2; //this equation can be replaced by the "mean function", for example, (Encoder(1)+Encoder(2)+Encoder(3))/3

    pidVelocity.error = pidVelocity.desired - Encoder * 10;// in the actual control, the effect of plusing 0.01 for Kp Ki Kd is too small. thus the error is multiplied 10 rather than change GUI's code 
    
    if(pidVelocity.error > VelocityLimit)//this part is to limit the error of Velocity
        pidVelocity.error = VelocityLimit;//if the Velocity's error is too lager, the result of Velocity will become limitation
    else if(pidVelocity.error < -VelocityLimit)//this part is to limit the error of Velocity
        pidVelocity.error = -VelocityLimit;//if the Velocity's error is too lager, the result of Velocity will become limitation
    velOutput= get_pid_vel(&pidVelocity,Distance_result);//in order to set intput of I_term, the output of velocity become this
    I_term = show_I_term();//show the change of I_term on GUI

    if(velOutput > velOutputLimit)//judge the velocity output
        velOutput = velOutputLimit;//if the velocity's output is too lager, the output of the veloctiy PID controller will become limitation
    else if(velOutput < -velOutputLimit)//judge the velocity output
        velOutput = -velOutputLimit;//if the velocity's output is too small, the output of the velocity PID controller will become limitation
    
    
    LastDistance_result = Distance_result;//record the last velocity
         
    return velOutput;//return the result of the velocity PID controller
}


////////////////////////////////////////////////////////////
//this funcition is to reset parameters of two PID controllers
////////////////////////////////////////////////////////////
void controllerResetAllPID(void)
{
  pidReset(&pidAngle);//reset angle PID controller
  pidReset(&pidVelocity);//reset velocity PID controller
}


////////////////////////////////////////////////////////////
//this funcition is to control the motor according to current PID controller
////////////////////////////////////////////////////////////
void MOTOR_Update(float Motor)
{
    if(Motor >= 1000)//this judgement limits the output of motor
    {
        Motor = 1000;
    }
    else if(Motor <= -1000)//this judgement limits the output of motor
    {   
        Motor = -1000;
    }
    if(Motor > 0)//this judgement can give the direction of current motor value. go forward
    {
        Motor_PWM.Fwd();//go forward
        Motor_PWM.Speed((float)Motor + offset_moving);//set the force to motor according to PID controllers
    }
    //if the balancer is under the load, the car cannot get enough force to make the movement at 10% PWM or 20% PWM 
    // after many times tests, the offset PWM is 40%
    
    if(Motor == 0)//if the output is 0, the motor will be commended to stop
    {
        Motor_PWM.Stop();
        Motor_PWM.Speed(Motor);
    }
    if(Motor < 0)//this judgement can give the direction of current motor value. go reserve
    {
        Motor_PWM.Rev();//go reserve 
        Motor_PWM.Speed(-(float)Motor + offset_moving);//set the force to motor according to PID controllers
    }   
}