A PID controller to control a buggie car that follows a line based on voltage variation detected by sensors attached to the car

Dependencies:   mbed C12832

main.cpp

Committer:
JTrindade
Date:
2021-03-08
Revision:
0:8609b4a06a8f

File content as of revision 0:8609b4a06a8f:



#include "mbed.h"
#include <stdlib.h>
#include <numeric>
#include <vector>
#include <iostream>
#include <fstream> 

PwmOut speed(p23);
PwmOut steering(p24);

//DigitalOut enable(p20);
AnalogIn sens_r(p15);
AnalogIn sens_l(p16);
AnalogIn feedback(p17);

//////////////]tuing
#include "C12832.h"
C12832 lcd(p5, p7, p6, p8, p11);
float mperiod = 1.0 / 20000;
float error_sensors = 0;
float error_steering = 0;
std::vector<float> total_error;
float u_drive = 0.5, u_steer = 0.5;
float integral = 0, derivative = 0;
float error_control = 0;
float last_error_s;
float position;
float max_turn = 0.635;
float min_turn = 0.23;
float mid_point = 0.503;
float offset = 0.5;
float p[3] = {1, 0, 0};
float dp[3] ={1, 1, 1};
float kp = 1;
float kd_s = 0.05, ki_s =  -2.19;
float kp_s = 6.05;
float temp = 0;

void calcIntegral();
void pidController();
float getErr(int t);
void twiddle();
////////////


int main()
{
    speed.period(mperiod);
    steering.period(mperiod);
    while(1){
        pidController();
    }
    twiddle();
    lcd.cls();
    lcd.locate(1,2);
    lcd.printf("kpf = %.2f, ki_s = %.2f, kd_s = %.2f", kp_s, ki_s, kd_s);
    return 0;
    
}

void pidController()
{
    error_sensors = sens_r.read() - sens_l.read();
    position = mid_point + error_sensors;
    if(position > max_turn) position = max_turn;
    if(position < min_turn) position = min_turn;
    error_steering = position - feedback.read();
    derivative = (error_steering - last_error_s)/mperiod; //derivative
    last_error_s = error_steering;
    u_drive = 0.8 - kp*abs(error_sensors);
    calcIntegral();
    u_steer = offset - kp_s*error_steering - ki_s*integral - kd_s*derivative;
    
    if (u_drive > 0.65) u_drive = 0.65; //to avoid damaging motors7
    else if(u_drive < 0.6) u_drive = 0.6;
    if (u_steer >= 0.7) u_steer = 0.7; //avoid locking motors
    if (u_steer <= 0.3) u_steer = 0.3; //avoid locking motors
    speed = u_drive;
    steering = u_steer;
}

float checkLimits(float val, int type){
    if(type){
        if(val > 0.8) return 0.8;
        else if(val < 0.2) return 0.2;
        return val;
    }
    if(val > max_turn) return max_turn;
    else if(val < min_turn) return min_turn;
    return val;
}

void calcIntegral(){
    //for integral part
    if (error_control < 10)
    {
        total_error.push_back(error_steering);
        error_control++;
    }
    else
    {
        total_error.erase(total_error.begin()); //removes vec first element
        total_error.push_back(error_steering);  //add current err as last to vec
    }
    integral = 0; //reset accumulated error
    for (int i = 0; i < total_error.size(); i++) integral += total_error[i] * mperiod;  //sum of errors in vector
}

void twiddle(){  
    float err = 0;
    float best_err  = getErr(0); //calc steering er
    float total_dp;
    
    for (int i = 0; i < 3; i++) total_dp += dp[i];
    while(total_dp > 0.005){
        for(int i =0; i < 3; i++){
            p[i]+=dp[i];
            err = getErr(0);

            if (err < best_err){
                best_err = err;
                dp[i] *= 1.1;
            }
            else{
                p[i] -= 2*dp[i];
                err = getErr(0);

                if(err < best_err){
                    best_err = err;
                    dp[i] *= 1.05;
                }
                else{
                    p[i] += dp[i];
                    dp[i] *= 0.95;
                }
            }
        }
    }
    std::ofstream outfile ("test.txt");
    outfile << "kp = " << p[0] << "\t ki = " << p[1] << "\t kd = " << p[2] << std::endl;
}

float getErr(int t){
    //////////apply new vals
    kp_s = p[0];
    ki_s = p[1];
    kd_s = p[2];
    pidController();
    error_sensors = sens_r.read() - sens_l.read();
    position = mid_point + error_sensors;
    if(position > max_turn) position = max_turn;
    if(position < min_turn) position = min_turn;
    error_steering = position - feedback.read();

    lcd.cls();
    lcd.locate(1,2);
    lcd.printf("kp:%.2f, ki:%.2f, kd:%.2f \nerr:%.2f", kp_s, ki_s, kd_s, error_steering);
    return error_steering;
}