ManualControl

Dependencies:   TPixy-Interface

Fork of MbedOS_Robot by ECE4333 - 2018 - Ahmed & Brandon

PiControlThread.cpp

Committer:
asobhy
Date:
2018-03-29
Revision:
23:1839085ffdcf
Parent:
22:c09acff62e6a

File content as of revision 23:1839085ffdcf:

/******************************************************************************/
// ECE4333
// LAB Partner 1:   Ahmed Sobhy - ID: 3594449
// LAB Partner 2:   Brandon Kingman - ID: 3470444
// Project:         Autonomous Robot Design
// Instructor:      Prof. Chris Diduch
/******************************************************************************/
// filename: PiControlThread.cpp
// file content description:
//      * Function to Create the PiControl Thread
//      * PiControl Thread
//      * PiControl ISR
//      * Variables related to the functionality of the thread
/******************************************************************************/

#include "mbed.h"
#include "ui.h"
#include "Drivers/motor_driver_r.h"
#include "Drivers/motor_driver_l.h"
#include "Drivers/DE0_driver.h"
#include "PiControlThread.h"
#include "Drivers/PiController.h"
#include "ui.h"
#include "CameraThread.h"



// setpoints
// speed
int setpointR = 0;
int setpointL = 0;

dp_t dpArray;

int iEnd;

bool memoryFull = false;
bool patrolStart = true;
bool reverse = true;
bool do180 = true;
int cnt=0;

//
int velR, velL;

// control signal
int32_t U_right, U_left;

sensors_t sensors;

void PiControlThread(void const *);
void PeriodicInterruptISR(void);

// steering gain
float Ks = 0.15;
// distance gain
float Kd = 10;

// overall robot required speed
int Setpoint;
Mutex mutexSetpoint;

osThreadId PiControlId;

/******************************************************************************/
//  osPriorityIdle          = -3,          ///< priority: idle (lowest)
//  osPriorityLow           = -2,          ///< priority: low
//  osPriorityBelowNormal   = -1,          ///< priority: below normal
//  osPriorityNormal        =  0,          ///< priority: normal (default)
//  osPriorityAboveNormal   = +1,          ///< priority: above normal
//  osPriorityHigh          = +2,          ///< priority: high
//  osPriorityRealtime      = +3,          ///< priority: realtime (highest)
/******************************************************************************/

// Declare PeriodicInterruptThread as a thread/process
osThreadDef(PiControlThread, osPriorityRealtime, 1024);

Ticker PeriodicInt;      // Declare a timer interrupt: PeriodicInt

/*******************************************************************************
* @brief    function that creates a thread for the PI controller. It initializes
*           the PI controller's gains and initializes the DC Motor. It also
*           initializes the PIControllerThread runs at 50ms period
* @param    none
* @return   none
*******************************************************************************/
void PiControlThreadInit()
{
    DE0_init();                  // initialize FPGA
    motorDriver_R_init();        // initialize motorDriver
    motorDriver_L_init();        // initialize motorDriver
    //                Kp,Ki
    PiController_init(1,0.4); // initialize the PI Controller gains and initialize variables

    PiControlId = osThreadCreate(osThread(PiControlThread), NULL);

    // Specify address of the PeriodicInt ISR as PiControllerISR, specify the interval
    // in seconds between interrupts, and start interrupt generation:
    PeriodicInt.attach(&PeriodicInterruptISR, 0.010);   // 10ms sampling period -> 100Hz freq

}

/*******************************************************************************
* @brief    This is the PI controller thread. It reads several values from the
*           FPGA such as speed, time and other sensors data
* @param    none
* @return   none
*******************************************************************************/
void PiControlThread(void const *argument)
{
    dpArray.i = 0;
    dpArray.size = ARRAY_SIZE;

    while (true) {

        osSignalWait(0x01, osWaitForever); // Go to sleep until signal, SignalPi, is received.

        // Get incremental position and time from QEI
        DE0_read(&sensors);

        // might not be needed
        sensors.dp_right = SaturateValue(sensors.dp_right, 112);
        sensors.dp_left = SaturateValue(sensors.dp_left, 112);

        // Maximum angular velocity @ dPostition = 112 is vel = 703 rad/sec
        //velR = (float)((6135.92 * sensors.dp_right) / sensors.dt_right) ;

        // Maximum angular velocity @ dPostition = 112 is vel = 703 rad/sec
        //velL = (float)((6135.92 * sensors.dp_left) / sensors.dt_left) ;

        // if manual control is ON use Differential drive
        if(MC) {
            /******************Manual Setpoint and Steering********************/
            mutexSetpoint.lock();
            setpointR = Setpoint + (Ks*SteeringError);
            setpointL = Setpoint - (Ks*SteeringError);
            mutexSetpoint.unlock();
            /******************Differential End********************************/

            // Make sure our limit is not exceeded
            setpointR = SaturateValue(setpointR, 112);
            setpointL = SaturateValue(setpointL, 112);

            /**********************Record Start********************************/
            // Record dp if there is room in memory
            if( (dpArray.i < dpArray.size) ) {

                // only record data when record button is pressed
                if(startRecording) {
                    dpArray.dpR[dpArray.i] = setpointR;
                    dpArray.dpL[dpArray.i] = setpointL;
                    dpArray.i++;
                    patrolStart = true;
                }

            } else {
                // memory is full
                memoryFull = true;
            }
            /************************Record End********************************/
            
            /*********************Playback Start*******************************/
        } else { // if manual control is not ON then Playback data

            // Check if its the first time to enter the patrol mode
            if(patrolStart) {
                // Store end index value
                iEnd = dpArray.i;
                // Reset playback index
                dpArray.i = 0;
                patrolStart = false;
            }

            // if do the 180 degree is true then do a 180 rotation
            if( do180 == true ) {
                // distance = 10ms * cnt * speed
                if ( cnt < 300 ) {
                    setpointR = -10;
                    setpointL = 10;
                    cnt++;
                }
                // exit the 180 code when done
                else {
                    do180 = false;
                    cnt = 0;
                }
            }
            else if ( dpArray.i < iEnd ) {
                
                // Data Playback normal direction
                if(!reverse) {
                    setpointR = dpArray.dpR[dpArray.i];
                    setpointL = dpArray.dpL[dpArray.i];
                }
                // Data Playback in reverse direction
                else {
                // Wheel dps are swaped to mantain correct direction playback
                    setpointR = dpArray.dpL[dpArray.i];
                    setpointL = dpArray.dpR[dpArray.i];
                }
                dpArray.i++;

            } else {
                // We reached the end of our playback we need to toggle reverse
                reverse = !reverse;
                // start from the beginning by reseting the index
                dpArray.i = 0;
                // Do a 180 degree turn
                do180 = true;
            }


            /***********************Playback End*******************************/
        }

        U_right = PiControllerR(setpointR,sensors.dp_right);
        U_left  = PiControllerL(setpointL,sensors.dp_left);

        // Set speed and direction for right motor
        if (U_right >= 0) {
            motorDriver_R_forward(U_right);
        } else if (U_right < 0) {
            motorDriver_R_reverse(U_right);
        }

        // Set speed and direction for left motor
        if (U_left >= 0) {
            motorDriver_L_forward(U_left);
        } else if (U_left < 0) {
            motorDriver_L_reverse(U_left);
        }

    }

}

/*******************************************************************************
* @brief    The ISR below signals the PIControllerThread. it is setup to run
*           every 10ms
* @param    none
* @return   none
*******************************************************************************/
void PeriodicInterruptISR(void)
{
    // Send signal to the thread with ID, PeriodicInterruptId, i.e., PeriodicInterruptThread.
    osSignalSet(PiControlId,0x1);
}